# Ansible Playbook 基础
# 基础
# ansible-playbook 常用选项
--step: 按步骤执行,每一步都需要操作员确认
--check: 检查playbook正确性,并运行干跑模式
--syntax-check: 仅检查语法错误
--list-tasks
--list-tags
--list-hosts
2
3
4
5
6
# Host 和 Users
- hosts: webservers
remote_user: yourname # 切换用户
become: yes
become_user: postgres
---
- hosts: webservers
remote_user: yourname # 全局默认的用户
tasks:
- service:
name: nginx
state: started
become: yes # 对某一个task开启用户切换
become_method: sudo # 切换方法为sudo,此外还可以使用su
2
3
4
5
6
7
8
9
10
11
12
13
# tasks
tasks:
- name: 运行一些命令,并忽略其输出内容
shell: /usr/bin/somecommand || /bin/true # 或者使用`ignore_errors: true`
- name: Copy ansible inventory file to client
copy: src=/etc/ansible/hosts dest=/etc/ansible/hosts # 使用缩进进行长句换行
owner=root group=root mode=0644
2
3
4
5
6
# handlers
当配置文件改变时,调用handlers触发重启
tasks:
- name: template configuration file
template:
src: template.j2
dest: /etc/foo.conf
notify:
- restart memcached
- restart apache
handlers:
- name: restart memcached
service:
name: memcached
state: restarted
- name: restart apache
service:
name: apache
state: restarted
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
在ansible2.2之后,可以使用listen
创建"主题",tasks会通知这些"主题"
handlers:
- name: restart memcached
service:
name: memcached
state: restarted
listen: "restart web services"
- name: restart apache
service:
name: apache
state: restarted
listen: "restart web services"
tasks:
- name: restart everything
command: echo "this task will restart the web services"
notify: "restart web services"
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 运行一个 Playbook
ansible-playbook [-C] playbook.yml [-f 10] [--list-hosts] [--verbose]
# -C 表示干跑测试模式,实际运行时应当取消, -f 为批次
2
# ansible-Pull
客户端主动拉取
# ansible-lint(语法检查)
playbook
语法及规范检查工具, 默认安装时并为安装, 使用yum install -y ansible-lint
进行安装即可
使用方法:
ansible-lint playbook.yaml
当然, 你也可以使用ansible-playbook
自带的ansible-playbook --syntax-check
来检查
# ansible-galaxy
ansible-galaxy
客户端允许您从Ansible Galaxy (opens new window)下载角色,并且还提供了一个出色的默认框架来创建您自己的角色.
# 进阶
# import_tasks & include_tasks
二者区别:
import*
: 预处理运行include*
: 中途运行
如果任务就一个的话,两个用哪个都无所谓.
tasks:
- import_tasks: common_tasks.yml
vars: # 可以向指定playbook传递参数
foot: bar
# or
- include_tasks: common_tasks.yml
# handlers中也可以使用
handlers:
- include_tasks: more_handlers.yml
# or
- import_tasks: more_handlers.yml
2
3
4
5
6
7
8
9
10
11
12
# Role
# Role 目录结构
roles/
├── dbsrvs
│ ├── defaults # 默认变量存放位置
│ ├── files # 所要传输或者使用的文件位置
│ ├── handlers
│ ├── meta # 元数据存放位置,可存放角色依赖,参考https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse_roles.html#role-dependencies
│ ├── tasks
│ ├── templates
│ └── vars # 变量存放位置
└── websrvs
├── files
├── handlers
├── tasks
├── templates
└── vars
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 示例及使用
# roles/example/tasks/main.yml
- name: added in 2.4, previously you used 'include'
import_tasks: redhat.yml
when: ansible_facts['os_family']|lower == 'redhat' # when相当于条件语句
- import_tasks: debian.yml
when: ansible_facts['os_family']|lower == 'debian'
# roles/example/tasks/redhat.yml
- yum:
name: "httpd"
state: present
# roles/example/tasks/debian.yml
- apt:
name: "apache2"
state: present
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 调用角色
- hosts: webservers
roles:
- example
- webservers
2
3
4
5
在ansible2.4之后,可以使用import_role
和include_role
:
- hosts: webservers
tasks:
- debug:
msg: "before we run our role"
- import_role:
name: example
- include_role:
name: example
- debug:
msg: "after we ran our role"
2
3
4
5
6
7
8
9
10
# 自定义role文件路径, 传递参数 ,tags
- hosts: webservers
tasks:
- include_role:
name: foo_app_instance
vars:
dir: '/path/to/my/roles/common'
app_port: 5000
when: "ansible_facts['os_family'] == 'RedHat'"
tags:
- web
- redhat
2
3
4
5
6
7
8
9
10
11
# variables
在playbook
中直接定义:
- hosts: webservers
vars:
http_port: 80
2
3
在文件中定义:
- hosts: all
remote_user: root
vars:
favcolor: blue
vars_files:
- /vars/external_vars.yml
2
3
4
5
6
# /vars/external_vars.yml
somevar: somevalue
password: magic
2
3
在命令行中传递:
ansible-playbook websrvs.yml --extra-vars "http_ver=2.4.6"
ansible-playbook release.yml --extra-vars "@some_file.json"
2
传递json
或者json file
参考:https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html#passing-variables-on-the-command-line
调用Facts
中的变量:
# 查看
ansible websrvs -m setup
# 调用
【【 ansible_facts['devices']['xvda']['model'] 】】 # 层级结构
【【 ansible_facts['nodename'] 】】
# 或者
【【 ansible_nodename 】】
2
3
4
5
6
7
8
ℹ️注意:默认情况下执行命令或者playbook会先收集facts
,如果你知道你不需要任何来自facts
的数据,那么可以使用以下参数来进行关闭:
- hosts: whatever
gather_facts: no
2
传递本地facts
:
在/etc/ansible/facts.d
目录下创建一个*.fact
的文件, 即可将本地facts
传递给主机setup
的ansible_local``facts
中去.
示例:
# /etc/ansible/facts.d/preferences.fact
[general]
asdf=1
bar=2
# 查看本地facts
ansible local -m setup -a "filter=ansible_local"
# 调用
【【 ansible_local['preferences']['general']['asdf'] 】】
# 或者
【【 ansible_local.prefetences.general.asdf 】】
2
3
4
5
6
7
8
9
10
详情参考:https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html#local-facts-facts-d
https://www.cnblogs.com/f-ck-need-u/p/7571974.html
注册与自定义变量:
- name: register vars
shell: echo bar
register: foo
- set_fact: var1="【【 foo.stdout 】】"
- set_fact: var2=" foo /// "
- debug: msg="【【 var2 】】 【【var1】】"
2
3
4
5
6
with_item
迭代变量
- name: with_items
shell: echo "【【 item 】】"
with_items:
- hello
- ansible
2
3
4
5
inventroy
主机组变量和主机变量
# /etc/ansible/hosts
[websvrs]
node01 var1="var1 node01"
node02
[websrvs:vars]
var2="var2 websrvs"
2
3
4
5
6
7
📓综合vars示例:
---
- hosts: localhost
gather_facts: yes
vars:
- http_port: 80
- https_port: 443
vars_files:
- /root/playbooks/vars/external_vars.yml
- /root/playbooks/vars/external_vars2.yml
tasks:
- name: show playbook vars
debug: msg=" the http_port is 【【 http_port 】】 /// https_port is 【【 https_port 】】 "
vars:
http_port: 8080
- name: import vars form localfile
debug: msg=" vars from localfile 【【 hello 】】 /// 【【 ansible 】】"
- name: import vars form local facts
debug: msg=" vars form local facts --- 【【 ansible_local.preferences.general.bar 】】 "
- name: import vars form commandline
debug: msg=" vars form commandline -- 【【 command 】】 "
ignore_errors: yes
- name: import vars form json file
debug: msg="ipv6 address is --- 【【 ipv6[0].address 】】"
- name: register vars
shell: echo bar
register: foo
- set_fact: var1="【【 foo.stdout 】】"
- set_fact: var2=" foo /// "
- debug: msg="【【 var2 】】 【【var1】】"
- name: with_items
shell: echo "【【 item 】】"
with_items:
- hello
- ansible
register: items
tags: items
- debug: var=items.results[0].stdout
tags: items
- debug: msg=" {% for i in items.results %} 【【 i.stdout 】】 {% endfor %} "
tags: items
- name: inventory var
debug: msg=" 【【 inventory_var1 】】 /// 【【 inventory_var2 】】 "
tags: inventory
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
🛩扩展阅读:
- jinja2 https://docs.ansible.com/ansible/latest/user_guide/playbooks_filters.html
- 特殊内置变量: https://docs.ansible.com/ansible/latest/reference_appendices/special_variables.html
# lineinfile
该模块确保文件中包含特定行,或使用向后引用的正则表达式替换现有行。
只适用于一行内容.
# NOTE: Before 2.3, option 'dest', 'destfile' or 'name' was used instead of 'path'
- name: 确保SElinux为enforce窗台
lineinfile:
path: /etc/selinux/config
regexp: '^SELINUX='
line: SELINUX=enforcing
- name: 确保wheel组不在sudoers配置文件中
lineinfile:
path: /etc/sudoers
state: absent
regexp: '^%wheel'
- name: 确保127.0.0.1为本地localhost
lineinfile:
path: /etc/hosts
regexp: '^127\.0\.0\.1'
line: 127.0.0.1 localhost
owner: root
group: root
mode: '0644'
- name: 确保httpd的监听端口为8080
lineinfile:
path: /etc/httpd/conf/httpd.conf
regexp: '^Listen '
insertafter: '^#Listen '
line: Listen 8080
- name: 确保注释在匹配文本上面
lineinfile:
path: /etc/services
regexp: '^# port for http'
insertbefore: '^www.*80/tcp'
line: '# port for http by default'
- name: 为空文件添加一行内容
lineinfile:
path: /tmp/testfile
line: 192.168.1.99 foo.lab.net foo
create: yes
# NOTE: Yaml requires escaping backslashes in double quotes but not in single quotes
- name: Ensure the JBoss memory settings are exactly as needed
lineinfile:
path: /opt/jboss-as/bin/standalone.conf
regexp: '^(.*)Xms(\\d+)m(.*)$'
line: '\1Xms${xms}m\3'
backrefs: yes
# NOTE: Fully quoted because of the ': ' on the line. See the Gotchas in the YAML docs.
- name: Validate the sudoers file before saving
lineinfile:
path: /etc/sudoers
state: present
regexp: '^%ADMIN ALL='
line: '%ADMIN ALL=(ALL) NOPASSWD: ALL'
validate: /usr/sbin/visudo -cf %s
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# replace
替换所有, 与lineinfile
不同
- name: Before Ansible 2.3, option 'dest', 'destfile' or 'name' was used instead of 'path'
replace:
path: /etc/hosts
regexp: '(\s+)old\.host\.name(\s+.*)?$'
replace: '\1new.host.name\2'
- name: Replace after the expression till the end of the file (requires Ansible >= 2.4)
replace:
path: /etc/apache2/sites-available/default.conf
after: 'NameVirtualHost [*]'
regexp: '^(.+)$'
replace: '# \1'
- name: Replace before the expression till the begin of the file (requires Ansible >= 2.4)
replace:
path: /etc/apache2/sites-available/default.conf
before: '# live site config'
regexp: '^(.+)$'
replace: '# \1'
# Prior to Ansible 2.7.10, using before and after in combination did the opposite of what was intended.
# see https://github.com/ansible/ansible/issues/31354 for details.
- name: Replace between the expressions (requires Ansible >= 2.4)
replace:
path: /etc/hosts
after: '<VirtualHost [*]>'
before: '</VirtualHost>'
regexp: '^(.+)$'
replace: '# \1'
- name: Supports common file attributes
replace:
path: /home/jdoe/.ssh/known_hosts
regexp: '^old\.host\.name[^\n]*\n'
owner: jdoe
group: jdoe
mode: '0644'
- name: Supports a validate command
replace:
path: /etc/apache/ports
regexp: '^(NameVirtualHost|Listen)\s+80\s*$'
replace: '\1 127.0.0.1:8080'
validate: '/usr/sbin/apache2ctl -f %s -t'
- name: Short form task (in ansible 2+) necessitates backslash-escaped sequences
replace: path=/etc/hosts regexp='\\b(localhost)(\\d*)\\b' replace='\\1\\2.localdomain\\2 \\1\\2'
- name: Long form task does not
replace:
path: /etc/hosts
regexp: '\b(localhost)(\d*)\b'
replace: '\1\2.localdomain\2 \1\2'
- name: Explicitly specifying positional matched groups in replacement
replace:
path: /etc/ssh/sshd_config
regexp: '^(ListenAddress[ ]+)[^\n]+$'
replace: '\g<1>0.0.0.0'
- name: Explicitly specifying named matched groups
replace:
path: /etc/ssh/sshd_config
regexp: '^(?P<dctv>ListenAddress[ ]+)(?P<host>[^\n]+)$'
replace: '#\g<dctv>\g<host>\n\g<dctv>0.0.0.0'
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# 参考链接
- Ansible Playbook : https://docs.ansible.com/ansible/latest/user_guide/playbooks_intro.html
- Ansible-Galaxy : https://galaxy.ansible.com/docs/?extIdCarryOver=true&sc_cid=701f2000001OH7YAAW